package com.example.demo.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.stream.Stream;

/**
 * @Author: ElonChung
 * @Date: 2020-05-19
 * @Description: HttpRequestAop
 */
@Slf4j
@Aspect
@Component
public class HttpRequestAop {
    public static long startTime;
    public static long endTime;

    /**
     * 切点表达式
     *
     * @PointCut 注解表示表示横切点，哪些方法需要被横切
     */
    @Pointcut("execution(* com.example.demo.controller.*.*(..))")

    /**
     * 切点签名
     */
    public void print() {
        log.info("【print()】");
    }

    @Before("print()")
    public void before(JoinPoint joinPoint) {
        log.info("前置切面before……");
        startTime = System.currentTimeMillis();
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String requestURI = request.getRequestURI();
        //这个方法取客户端ip"不够好"
        String remoteAddr = request.getRemoteAddr();
        String requestMethod = request.getMethod();
        String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        StringBuffer buffer = new StringBuffer();
        Stream.of(args).forEach(a -> {
            buffer.append(a.toString() + ",");
        });
        log.info("请求url=" + requestURI + ",客户端ip=" + remoteAddr + ",请求方式=" + requestMethod + ",请求的类名=" + declaringTypeName + ",方法名=" + methodName);
        log.info("入参=" + buffer.toString());
    }

    @After("print()")
    public void after() {
        endTime = System.currentTimeMillis() - startTime;
        log.info("后置切面after……");
    }

    /**
     * @param object
     * @AfterReturning 注解用于获取方法的返回值
     */
    @AfterReturning(pointcut = "print()", returning = "object")
    public void getAfterReturn(Object object) {
        log.info("本次接口耗时={}ms", endTime);
        if (object != null) {
            log.info("afterReturning={}", object.toString());
        }
    }
}
